package jannex.query;

import jannex.mapping.ResultSetHandler;
import jannex.query.conditional.Equal;

public class QueryBuilder<E> {

    private final ResultSetHandler<E> handler;

    public QueryBuilder(ResultSetHandler<E> handler) {
        this.handler = handler;
    }

    public Select<E> select(String... fields) {
        return new Select<>(handler, fields);
    }

    public Select<E> select() {
        return new Select<>(handler);
    }

    public Select<E> select(E e) {
        return null;
    }

    public Update<E> update() {
        return new Update<>(handler);
    }

    public Update<E> update(E e) {
//        Update<E> update = new Update<>((Class<E>) e.getClass());
//        update.where(e);
//        return update;
        return null;
    }

    public PlannedStatement<Void> raw(String sql) {
        return null;
    }



    String example =
            "SELECT DISTINCT " +
                    "   batches.*, " +
                    "   flows.rank " +
                    "FROM " +
                    "   flow.batches_undeleted AS batches, " +
                    "   flow.flows_undeleted AS flows, " +
                    "   flow.flowstep_instances AS instances, " +
                    "   flow.flowstep_instances_groups AS groups " +
                    "WHERE " +
                    "   batches.flowId = instances.flowId " +
                    "   AND flows.domainId = ? " +
                    "   AND batches.flowId = flows.id " +
                    "   AND batches.finishedDate IS NULL " +
                    "   AND groups.flowstepInstanceId = instances.id " +
                    "   AND groups.groupId IN (asdf) " +
                    "ORDER BY " +
                    "   flows.rank, " +
                    "   batches.finishedDate DESC, " +
                    "   batches.priority, " +
                    "   batches.createdDate";


    String hardWindow =
            "SELECT SalesOrderID, ProductID, OrderQty\n" +
                    "    ,SUM(OrderQty) OVER(PARTITION BY SalesOrderID) AS Total\n" +
                    "    ,AVG(OrderQty) OVER(PARTITION BY SalesOrderID) AS \"Avg\"\n" +
                    "    ,COUNT(OrderQty) OVER(PARTITION BY SalesOrderID) AS \"Count\"\n" +
                    "    ,MIN(OrderQty) OVER(PARTITION BY SalesOrderID) AS \"Min\"\n" +
                    "    ,MAX(OrderQty) OVER(PARTITION BY SalesOrderID) AS \"Max\"\n" +
                    "FROM Sales.SalesOrderDetail \n" +
                    "WHERE SalesOrderID IN(43659,43664);";

    String window =
            "SELECT * FROM (\n"+
                    "  SELECT\n"+
                    "    ROW_NUMBER() OVER (ORDER BY key ASC) AS rownumber,\n"+
                    "    columns\n"+
                    "  FROM tablename\n"+
                    ") AS foo\n"+
                    "WHERE rownumber <= n";

    String cases =
            "SELECT   ProductNumber, Name, \"Price Range\" = \n" +
                    "  CASE \n" +
                    "     WHEN ListPrice =  0 THEN 'Mfg item - not for resale'\n" +
                    "     WHEN ListPrice < 50 THEN 'Under $50'\n" +
                    "     WHEN ListPrice >= 50 and ListPrice < 250 THEN 'Under $250'\n" +
                    "     WHEN ListPrice >= 250 and ListPrice < 1000 THEN 'Under $1000'\n" +
                    "     ELSE 'Over $1000'\n" +
                    "  END\n" +
                    "FROM Production.Product\n" +
                    "ORDER BY ProductNumber ;";


    private static class SalesOrderDetail {
        private String salesOrderId;
        private String productId;
        private String orderQty;
    }

    private static class Person {
        private String firstName;
        private String lastName;

        private Person(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
    }

    public static void main(String[] args) throws CloneNotSupportedException {

        QueryBuilder<Person> builder = new QueryBuilder<>(null);

        Person person = new Person("rasmus", "ros");

        // Build parts
        Where<Person> where = new Where<Person>().equal("firstName", "rasmus");

        Select<Person> persons =
                builder.select().<Select<Person>>clause(where).statement();

        Select<Person> persons2 = builder
                .select(person).where() // where replaces select where
                .equal("socialSecurityNumber", "870808-6213")
                .statement();
        Select<Person> persons2And = builder
                .select(person).append().where() // where adds to old where
                .equal("socialSecurityNumber", "870808-6213")
                .statement();

        Update<Person> personUpdate = builder
                .update(person).set("password", "awesome").statement();
        Update<Person> personWhereUpdate = builder
                .update().set("password", "awesome").where(person).statement();

        Select<Person> persons3 = builder.select(new Person("rasmus", "ros"));

        builder.select().from("persons");
        builder.select().where();

//        Select<SalesOrderDetail> select = new Select<>(null)
//                .columns()
//                .sum("OrderQty").over().partitionBy("SalesOrderID").as("Total")
//                .avg("OrderQty").over().partitionBy("SalesOrderID").as("Avg")
//                .from("Sales.SalesOrderDetail")
//                .where().in("SalesOrderId", 46359, 43664).query();


        String example =
                "SELECT DISTINCT " +
                        "   batches.*, " +
                        "   flows.rank " +
                        "FROM " +
                        "   flow.batches_undeleted AS batches, " +
                        "   flow.flows_undeleted AS flows, " +
                        "   flow.flowstep_instances AS instances, " +
                        "   flow.flowstep_instances_groups AS groups " +
                        "WHERE " +
                        "   batches.flowId = instances.flowId " +
                        "   AND flows.domainId = ? " +
                        "   AND batches.flowId = flows.id " +
                        "   AND batches.finishedDate IS NULL " +
                        "   AND groups.flowstepInstanceId = instances.id " +
                        "   AND groups.groupId IN (asdf) " +
                        "ORDER BY " +
                        "   flows.rank, " +
                        "   batches.finishedDate DESC, " +
                        "   batches.priority, " +
                        "   batches.createdDate";

//        PreparedStatement test = new Select<>(Integer.class, "batches.*", "flows.rank").distinct()
//                .from("flow.batches_undeleted").as("batches")
//                .and("flow.flows_undeleted").as("flows")
//                .and("flow.flowstep_instances").as("instances")
//                .and("flow.flowstep_instances_groups").as("groups")
//                .where()
//                .equal("batches.flowId", "instances.flowId").literal()
//                .equal("flows.domainId", 1)
//                .equal("batches.flowId", "flows.id").literal()
//                .isNull("batches.finishedDate")
//                .equal("groups.flowstepInstanceId", "instances.id").literal()
//                .in("groups.groupId", 1, 3, 2)
//                .orderBy("flows.rank", "batches.finishedDate DESC",
//                        "batches.priority", "batches.createdDate")
//                .prepare();

        builder.select("batches.*", "flows.rank").distinct()
                .from(
                        new Table("flow.batches_undeleted").as("batches"),
                        new Table("flow.flows_undeleted").as("flows"),
                        new Table("flow.flowstep_instances").as("instances"),
                        new Table("flow.flowstep_instances_groups").as("groups"))
                .where(
                        new Equal("batches.flowId", "instances.flowId").literal(),
                        new Equal("flows.domainId", 1));

    }

}
